package service

import (
	"errors"
	"fmt"
	beego "github.com/beego/beego/v2/server/web"
	"ksd-social-api/commons/page"
	"ksd-social-api/commons/tools"
	cservice "ksd-social-api/modules/channel/service"
	"ksd-social-api/modules/note/model"
	"ksd-social-api/modules/note/model/context"
	"ksd-social-api/modules/note/model/vo"
	"ksd-social-api/utils"
	"ksd-social-api/utils/rdb"
	"strconv"
	"time"
)

type NoteService struct{}

var noteStudyUserRecordsService = NoteStudyUserRecordsService{}
var noteChapterService = NoteChapterService{}
var channelService = cservice.ChannelService{}

/**
 * @desc 保存用户的文章浏览记录
 * @author feige
 * @date 2023-11-14
 * @version 1.0
 */
func (service *NoteService) UpdateNoteVideo(ctx *context.NoteVideoContext) bool {
	// 保存入库
	flag := noteMapper.UpdateNoteVideo(ctx.Id.Uint64(), ctx.Title, ctx.Img, ctx.Videoid, ctx.PanLink, ctx.PanPwd, ctx.SystemId)
	return flag
}

/*
*
更新视频id
*/
func (service *NoteService) UpdateNoteVideoId(ctx *context.NoteVideoContext) bool {
	// 保存入库
	flag := noteMapper.UpdateNoteVideoId(ctx.Id.Uint64(), ctx.Videoid, ctx.SystemId)
	return flag
}

/*
复制课程
*/
func (service *NoteService) CopyNote(id uint64, systemId uint64) uint64 {
	// 保存入库
	note, _ := noteMapper.GetById(id, systemId)
	note.Id = 0
	note.Status = 0
	id = noteMapper.SaveUpdateNoteVideo(*note)
	return id
}

/*
*
保存课程
*/
func (service *NoteService) SaveUpdateNoteVideo(ctx *context.NoteContext) uint64 {
	// 保存入库
	var note model.Note
	utils.CopyProperties(&note, ctx)
	parseUint, _ := strconv.ParseUint(ctx.Id, 10, 64)
	note.Id = parseUint
	id := noteMapper.SaveUpdateNoteVideo(note)
	return id
}

/**
 * @author feige
 * @date 2023-10-08
 * @desc 根据id查询资源信息，不包含内容
 */
func (service *NoteService) GetNoteByIDToPay(noteId uint64, systemId uint64) (pvo *vo.NoteDetailPayVo, err error) {
	// 1: 根据id查询数据层
	note, err := noteMapper.GetByIdTOPay(noteId, systemId)
	if err != nil {
		return nil, err
	}
	noteDetailPayVo := vo.NoteDetailPayVo{}
	utils.CopyProperties(&noteDetailPayVo, note)
	return &noteDetailPayVo, nil
}

/**
 * @author feige
 * @date 2023-10-08
 * @desc 根据id查询资源信息的业务蹭
 */
func (service *NoteService) GetNoteByID(noteId uint64, systemId uint64, flag bool) (pvo *vo.NoteDetailVo, err error) {
	// 1: 根据id查询数据层
	note, err := noteMapper.GetById(noteId, systemId)
	if err != nil {
		return nil, err
	}

	noteDetailVo := vo.NoteDetailVo{}
	utils.CopyProperties(&noteDetailVo, note)
	if noteDetailVo.ChapterFlag == 2 {
		// 笔记章节
		noteDetailVo.ChapterList, _ = noteChapterService.FindChapterLessons(noteId, systemId)
	}
	// 章绑定节
	return &noteDetailVo, err
}

/**
 * @author feige
 * @date 2023-10-08
 * @desc 根据id查询资源信息的业务蹭
 */
func (service *NoteService) GetNoteDetailByID(noteId uint64, userId uint64, systemId uint64) (pvo *vo.NoteDetailVo, err error) {
	noteDetailVo := vo.NoteDetailVo{}
	// 1: 根据id查询数据层
	note, err := noteMapper.GetById(noteId, systemId)

	if err != nil {
		return nil, errors.New("查无此资源")
	}

	utils.CopyProperties(&noteDetailVo, note)
	// 获取评分
	noteDetailVo.Score = commentMapper.SumSocre(noteId, systemId)
	if noteDetailVo.Score == 0 {
		noteDetailVo.Score = 5
	}

	if note.ChapterFlag == 2 {
		// 笔记章节
		noteDetailVo.ChapterList, _ = noteChapterService.FindChapterLessonsStatus(noteId, systemId)
	}
	note.Content = ""
	// 用户相关的操作和统计
	if userId > 0 {
		// 收藏
		noteDetailVo.FavFlag = noteUserFavMapper.CountNoteUserFav(userId, noteId, systemId)
		// 判断用户是否购买此资源
		noteDetailVo.BuyFlag, _ = service.ValidatorUserNoteMain(&noteDetailVo, userId, noteId, systemId)
		if noteDetailVo.BuyFlag == 0 {
			noteDetailVo.HtmlContent = utils.HtmlParseSubstr(noteDetailVo.HtmlContent, 1200)
		}
		// 购买人数
		noteDetailVo.BuyNum = userBuyNoteMapper.CountUserBuyNoteNo(userId, noteId, systemId)
		// 查询用户已学的章节
		noteDetailVo.UserStudyRecords = noteStudyUserRecordsService.FindNoteStudyUserRecordsByUN(userId, noteId, systemId)
		if noteDetailVo.BuyFlag <= 0 {
			noteDetailVo.PanPwd = ""
		}
	} else {
		if note.PayFlag == 2 {
			noteDetailVo.HtmlContent = utils.HtmlParseSubstr(noteDetailVo.HtmlContent, 1200)
		}
	}

	// 章绑定节
	return &noteDetailVo, nil
}

/**
 * @author feige
 * @date 2023-10-16
 * @version 1.0
 * @desc 资源用户收藏
 */
func (service *NoteService) FavNoteByUserId(userId uint64, noteId uint64, systemId uint64) (bool, error) {
	// 1: 获取redis的rdb对象,目标： sadd ksd:note:1 1
	cacheKey := fmt.Sprintf("COURSE:FAV:%d:%d", noteId, systemId)
	// 2: 完成redis收藏功能
	err := rdb.RdbSAdd(cacheKey, fmt.Sprintf("%d", userId))
	if err != nil {
		return false, err
	}
	// 3: 预留把资源的收藏数量+1
	return true, nil
}

/**
 * @author feige
 * @date 2023-10-16
 * @version 1.0
 * @desc 资源用户取消收藏
 */
func (service *NoteService) UnFavNoteByUserId(userId uint64, noteId uint64, systemId uint64) (bool, error) {
	// 1: 获取redis的rdb对象,目标： sadd ksd:note:1 1
	cacheKey := fmt.Sprintf("COURSE:FAV:%d:%d", noteId, systemId)
	// 2: 完成redis收藏功能
	_, err := rdb.RdbSREM(cacheKey, fmt.Sprintf("%d", userId))
	if err != nil {
		return false, err
	}
	// 3: 预留把资源的收藏数量+1
	return true, nil
}

/**
* @author feige
* @date 2023-10-16
* @version 1.0
* @desc 点赞
 */
func (service *NoteService) LikeNote(userId uint64, noteId uint64, systemId uint64) (bool, error) {
	// 1: 获取rdb对象
	cacheKey := fmt.Sprintf("COURSE:LIKE:%d:%d", noteId, systemId)
	// 2:添加广告
	err := rdb.RdbSAdd(cacheKey, fmt.Sprintf("%d", userId))
	if err != nil {
		return false, err
	}
	return true, nil
}

/**
* @author feige
* @date 2023-10-16
* @version 1.0
* @desc 点赞
 */
func (service *NoteService) UnLikeNote(userId uint64, noteId uint64, systemId uint64) (bool, error) {
	// 1: 获取rdb对象
	cacheKey := fmt.Sprintf("COURSE:LIKE:%d:%d", noteId, systemId)
	// 2:添加广告
	_, err := rdb.RdbSREM(cacheKey, fmt.Sprintf("%d", userId))
	if err != nil {
		return false, err
	}
	return true, nil
}

/*
* @desc 更新浏览数
* @author feige
* @date 2023-11-14
* @version 1.0
 */
func (service *NoteService) UpdateViewCount(opid uint64, ip string, systemId uint64) bool {
	if service.CheckLimitViewCount(opid, ip, systemId) {
		return noteMapper.UpdateViewCount(opid, systemId)
	}
	return true
}

/**
 * 评论的频率检查
 * @author feige
 * @date 2023-11-21
 * @version 1.0
 * @desc
 */
func (service *NoteService) CheckLimitViewCount(opid uint64, ip string, systemId uint64) bool {
	// 时间频率限制 commentIntervalSeconds == -1不限制，否则就会限制
	// 5代表用户在5秒之内只能评论一次，如果超过在5秒之内提交N次就不停的提示：操作繁忙
	commentIntervalSeconds := beego.AppConfig.DefaultInt("viewcount.limit.seconds", 3)
	if commentIntervalSeconds > 0 {
		result := service.GetCommentInterval(opid, ip, systemId, commentIntervalSeconds)
		if !result {
			return false
		}
	}

	return true
}

/**
 * 这里就是setnxex的代码
 * @author feige
 * @date 2023-11-21
 * @version 1.0
 * @desc
 */
func (service *NoteService) GetCommentInterval(opid uint64, ip string, systemId uint64, intervalTime int) bool {
	key := fmt.Sprintf("note:viewcount:interval:%s:%s:%d", opid, ip, systemId)
	result := rdb.RdbSetEXNX(key, opid, intervalTime)
	return result
}

/**
 * @desc 保存用户的文章浏览记录
 * @author feige
 * @date 2023-11-14
 * @version 1.0
 */
func (service *NoteService) SaveUserNoteHits(noteUserHitsContext *context.NoteUserHitsContext) bool {
	// 接受传递过来的参数
	var noteUserHits model.NoteUserHits
	utils.CopyProperties(&noteUserHits, noteUserHitsContext)
	// 保存入库
	flag := noteMapper.SaveUserNoteHits(&noteUserHits)
	return flag
}

/**
 * @author feige
 * @date 2023-10-13
 * @version 1.0
 * @desc 查询资源列表信息，栏目和搜索使用
 */
func (service NoteService) FindNoteListAndPage(ctx context.NoteSearchContext) *page.Page {
	p, _ := noteMapper.FindNoteListAndPage(ctx)
	notes := p.Records.([]model.Note)
	noteVos := []vo.NoteVo{}
	for _, note := range notes {
		// 3: 查询当前登录的用户信息和资源id去查询用户资源收藏表
		noteVo := vo.NoteVo{}
		utils.CopyProperties(&noteVo, note)
		// 2: 如果没有错误就必须把model数据导入vo数据中
		noteVos = append(noteVos, noteVo)
	}

	p.Records = noteVos
	return p
}

/**
 * @author feige
 * @date 2023-10-13
 * @version 1.0
 * @desc 查询小册列表信息，栏目和搜索使用
 */
func (service NoteService) FindPushNoteListAndPage(ctx context.NoteSearchContext) *page.Page {
	noteVos := []vo.NoteVo{}
	p := noteMapper.FindPushNoteListAndPage(ctx.PageNo, ctx.PageSize, ctx.ChannelId, ctx.SystemId)
	notes := p.Records.([]model.Note)
	for _, note := range notes {
		// 3: 查询当前登录的用户信息和小册id去查询用户小册收藏表
		noteVo := vo.NoteVo{}
		utils.CopyProperties(&noteVo, note)
		// 2: 如果没有错误就必须把model数据导入vo数据中
		noteVos = append(noteVos, noteVo)
	}
	p.Records = noteVos
	return p
}

/**
 * 验证用户是否购买小册
 * @author feige
 * @date 2023-12-13
 * @version 1.0
 * @desc
 */
func (service *NoteService) ValidatorUserNoteMain(noteDetailVo *vo.NoteDetailVo, userId uint64, noteId uint64, systemId uint64) (int, error) {
	note, _ := noteMapper.GetById(noteId, systemId)
	if noteDetailVo != nil {
		noteDetailVo.Viewcount = note.Viewcount
		noteDetailVo.FavNum = note.FavNum
	}
	// 1: 如果小册是免费的，直接通过
	if note.PayFlag <= 1 {
		return 1, nil
	}
	//如果是作者本身也可以查看
	if note.Userid == userId {
		return 1, nil
	}
	//2: 查看是不是超级会员或者管理员，直接通过
	user := userMapper.GetUserByID(userId, systemId)
	if user.Role == "admin" || user.VipFlag == 7 || (user.VipFlag > 1 && user.VipTime.After(time.Now())) {
		return 1, nil
	}
	// 3: 是否订阅了小册
	countUserBuyNoteNo := userBuyNoteMapper.CountUserBuyNoteNo(userId, noteId, systemId)
	if countUserBuyNoteNo > 0 {
		return 1, nil
	}
	// 4: 是否订阅了栏目
	buyChannelNo := channelService.CountUserBuyChannelNo(userId, note.ChannelId, systemId)
	if buyChannelNo > 0 {
		return 1, nil
	}
	// 5: 如果购买了专题
	countUserBuy, _ := specialBuyMapper.CountUserBuyNote(noteId, userId, systemId)
	if countUserBuy > 0 {
		return 1, nil
	}

	return 0, errors.New("你尚未订阅资源，无法学习！")
}

/**
 * 查询笔记上一篇下一篇
 * @author feige
 * @date 2024-04-17
 * @version 1.0
 * @desc
 */
func (service *NoteService) FindNotePrevNext(categoryId uint64, systemId uint64) ([]*vo.NotePrevNextVo, error) {
	cacheKey := fmt.Sprintf("SYSTEM:NOTE:FindNotePrevNext:%d:%d", categoryId, systemId)
	checkKey := rdb.RdbCheck(cacheKey)
	noteDetailVos := []*vo.NotePrevNextVo{}
	if checkKey {
		jsonString, _ := rdb.RdbGet(cacheKey)
		if len(jsonString) == 0 {
			return nil, errors.New("查无此资源")
		}
		tools.JsontoStruct(jsonString, &noteDetailVos)
	} else {
		noteDetailVos = noteMapper.FindNotePrevNext(categoryId, systemId)
		rdb.RdbSetEX(cacheKey, tools.StructToJson(noteDetailVos), 60*60*24)
	}
	return noteDetailVos, nil
}

/**
 * @author feige
 * @date 2023-10-17
 * @version 1.0
 * @desc 统计个人中心各模块的学习数量
 */
func (service *NoteService) CountNoteAll(channelId int64) []*vo.NoteMessageVo {
	return noteMapper.CountNoteAll(channelId)
}
